package com.damai.utils;

import java.lang.reflect.Method;

import com.citywithincity.reflect.CtClassUtil;
import com.citywithincity.utils.ClassUtil;
import com.citywithincity.utils.StringUtils;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.Modifier;
import javassist.NotFoundException;

public class CtClassBuilder {
	
	private String name;
	private CtClass clazz;
	ClassPool pool = ClassPool.getDefault();
	
	
	public CtClassBuilder(String name){
		this.name = name;
		clazz = pool.makeClass(name);
	}
	
	public void setSuperClass(Class<?> clazz) throws CannotCompileException, NotFoundException{
		this.clazz.setSuperclass(pool.get(clazz.getName()));
	}
	
	public static String callStatic(Class<?> clazz, String name){
		return new StringBuilder().append(clazz.getName()).append(".").append(name).append("()").toString();
	}
	public static String callStatic(Class<?> clazz, String name,String...args){
		return new StringBuilder().append(clazz.getName()).append(".").append(name).append("(").append(StringUtils.join(args)).append(")").toString();
	}
	
	public CtClassBuilder beginInterface(Class<?> interfaceClass) throws NotFoundException{
		clazz.addInterface(pool.get(interfaceClass.getName()));
		return this;
	}
	
	public CtClassBuilder addInterfaceFromBase(Class<?> base) throws NotFoundException{
		for( Class<?> inter : base.getInterfaces()  ){
			clazz.addInterface(pool.get(inter.getName()));
		}
		return this;
		
	}
	
	private CtMethodBuilder methodBuilder;
	
	public CtMethodBuilder beginMethod(Method method) throws NotFoundException{
		methodBuilder= new CtMethodBuilder(this).setMethod(method);
		return methodBuilder;
	}
	public CtClassBuilder endMethod() throws CannotCompileException {
		clazz.addMethod(methodBuilder.getMethod());
		return this;
	}
	
	private Class<?> realClass;
	public CtClassBuilder make() throws CannotCompileException{
		realClass = clazz.toClass();
		return this;
	}
	
	@SuppressWarnings("unchecked")
	public <T> T newInstance() throws InstantiationException, IllegalAccessException{
		return (T)realClass.newInstance();
	}
	
	@SuppressWarnings("unchecked")
	public <T> T newInstance(Object[] args) throws Exception{
		return (T) ClassUtil.newInstance(realClass, args);
	}
	
	public CtClassBuilder addField(Class<?> fieldClass,String name,int modifiers) throws CannotCompileException{
		return addField("private "+fieldClass.getName() + " " + name + ";",modifiers);
	}
	public CtClassBuilder addArrayField(Class<?> fieldClass,String name,int modifiers) throws CannotCompileException{
		return addField("private "+fieldClass.getName() + "[] " + name + ";",modifiers);
	}
	public CtClassBuilder addField(String content,int modifiers) throws CannotCompileException{
		CtField field = CtField.make(content, clazz);
		clazz.addField(field);
		field.setModifiers(modifiers);
		return this;
	}
	public CtClassBuilder addContructor(String body) throws CannotCompileException{
		
		CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
		constructor.setBody(body);
		clazz.addConstructor(constructor);
		return this;
	}
	
	
	public CtClassBuilder addContructor(Class<?>[] params,String body) throws CannotCompileException, NotFoundException{
		CtConstructor constructor = new CtConstructor(CtClassUtil.toCtClassTypes(params), clazz);
		constructor.setBody(body);
		clazz.addConstructor(constructor);
		return this;
	}
	
	public CtClassBuilder letFiledEq(String field,String content){
		
		return this;
	}
	
	public CtClassBuilder endContructor(){
		
		return this;
	}


	public CtClass getClazz() {
		
		return clazz;
	}


	public Class<?> getRealClass() {
		return realClass;
	}



	
}
